<script setup lang="ts">
import type { StudyTreeItem } from '@/views/Square/LearningSquare/SkillTree/home/types/StudyTreeItem';
import NodeDetails from '@/views/Square/LearningSquare/SkillTree/details/Components/NodeDetails.vue';
import { Position, VueFlow } from "@vue-flow/core";
import type { NodeTypesObject } from "@vue-flow/core";
import { MiniMap } from '@vue-flow/minimap'
import { markRaw, onMounted, ref } from 'vue';
import { message } from 'ant-design-vue';
import { Controls } from '@vue-flow/controls'
import FlowRootNode from '@/views/Square/LearningSquare/SkillTree/details/CustomNodes/RootNode.vue';
import FlowTrunkNode from '@/views/Square/LearningSquare/SkillTree/details/CustomNodes/TrunkNode.vue';
import FlowBranchNode from '@/views/Square/LearningSquare/SkillTree/details/CustomNodes/BranchNode.vue';

// 资源链接的结构
export interface Link {
  url: string;
  type: string;
  title: string;
  link: string; // 现在是必需的
}

// 分支节点的结构
interface BranchNode {
  index: string;
  title: string;
  description: string;
  status: string;
  remark: string;
  links: Link[];
  branch?: BranchNode[];
}

// VueFlow 节点的接口
export interface VueFlowNode {
  id: string;
  position: { x: number; y: number };
  data: { label: string, links: Link[] };
  type: 'root_node' | 'trunk_node' | 'branch_node';
}

// VueFlow 边的接口
interface VueFlowEdge {
  id: string;
  source: string;
  target: string;
  animated?: boolean;
  class: 'trunk_edge' | 'branch_edge';
  style?: { stroke: string, strokeWidth: number };
  sourceHandle?: Position;
  targetHandle?: Position;
}

const props = defineProps<{ studyTreeDetails: StudyTreeItem, treeName: string }>();
const parsedJsonContent = JSON.parse(props.studyTreeDetails.jsonContent);
const rootNodeId = ref<string>("0");
const isDrawerOpen = ref<boolean>(false);
const selectedNode = ref<VueFlowNode>();
const trunkEdgeStyle = {
  stroke: 'orange',
  strokeWidth: 4,
};
const branchEdgeStyle = {
  stroke: 'lightblue',
  strokeWidth: 2,
};

const nodes = ref<VueFlowNode[]>([]);
const edges = ref<VueFlowEdge[]>([]);
const nodeTypes = {
  root_node: markRaw(FlowRootNode),
  trunk_node: markRaw(FlowTrunkNode),
  branch_node: markRaw(FlowBranchNode),
}

const initNodes = () => {
  // 递归遍历节点并添加到nodes中
  const recursion = (rootNode: BranchNode) => {
    for (const item of rootNode.branch || []) {
      nodes.value.push({
        id: item.index,
        position: { x: 0, y: 0 },
        data: { label: `${item.index} ${item.title}`, links: item.links },
        type: 'branch_node',
      });
      recursion(item);
    }
  }

  // 添加根节点
  nodes.value.push({
    id: rootNodeId.value,
    position: { x: 0, y: 0 },
    data: { label: props.treeName, links: [] },
    type: 'root_node',
  });

  // 遍历一级节点
  for (const item of parsedJsonContent) {
    nodes.value.push({
      id: item.index,
      position: { x: 0, y: 0 },
      data: { label: `${item.index} ${item.title}`, links: item.links },
      type: 'trunk_node',
    });
    recursion(item);
  }
}

const initEdges = () => {
  for (const item of nodes.value) {
    if (item.id !== rootNodeId.value) {
      const currentNodeId = item.id;

      // 获取父节点index
      // 先判断是不是整数
      if (Number.isInteger(Number(currentNodeId))) {
        // 与根节点相连
        edges.value.push({
          id: `${rootNodeId.value}-${currentNodeId}`,
          source: rootNodeId.value,
          target: currentNodeId,
          animated: true,
          class: 'trunk_edge',
          style: trunkEdgeStyle,
          sourceHandle: Position.Bottom,
          targetHandle: Position.Top,
        });

        // 对于不是1的整数节点，还与前一个整数节点相连
        if (currentNodeId !== "1") {
          const previousNodeId = String(Number(currentNodeId) - 1);
          edges.value.push({
            id: `${previousNodeId}-${currentNodeId}`,
            source: previousNodeId,
            target: currentNodeId,
            animated: true,
            class: 'trunk_edge',
            style: trunkEdgeStyle,
            sourceHandle: Position.Right,
            targetHandle: Position.Left,
          });
        }
      }
      else {
        // 对于非整数节点，与其父节点相连
        const parentNodeId = currentNodeId.substring(0, currentNodeId.lastIndexOf("."));
        edges.value.push({
          id: `${parentNodeId}-${currentNodeId}`,
          source: parentNodeId,
          target: currentNodeId,
          animated: true,
          class: 'branch_edge',
          style: branchEdgeStyle,
          sourceHandle: Position.Bottom,
          targetHandle: Position.Left,
        });
      }
    }
  }
}

// 根据id获取节点
const getNodeById = (id: string) => {
  return nodes.value.find(node => node.id === id);
}

// 获取id的第一个数字，用于判断节点是否在同一簇
const getFirstIdNumber = (id: string) => {
  return Number(id.split('.')[0]);
}

// 获取节点在nodes中的index，用获取列表中节点位置
const getNodeIndex = (id: string) => {
  return nodes.value.findIndex(node => node.id === id);
}

// 获取节点层级，用于计算节点x位置
const getNodeLevel = (id: string) => {
  return id.split('.').length;
}

// 获取前一簇的最大x坐标，用于主节点x位置
const getPriorCrowdMaxX = (id: string) => {
  const idFirstNumber = getFirstIdNumber(id);
  const priorCrowd = nodes.value.filter(node => getFirstIdNumber(node.id) === (idFirstNumber - 1));
  return priorCrowd.reduce((maxX, node) => Math.max(maxX, node.position.x), 0);
}

// 布局函数，设置每一个节点位置。
// 对于主节点，设置y位置为0，x位置为前一簇的最大x坐标加上偏移值
// 对于子节点，设置y位置为列表中前一节点y位置加上偏移值，x位置由根节点x位置加上层级*偏移值
const setNodesPosition = () => {
  for (const item of nodes.value) {
    if (item.id !== rootNodeId.value) {
      const idFirstNumber = getFirstIdNumber(item.id); // 获取id的第一个数字
      const nodeIndex = getNodeIndex(item.id); // 获取节点在nodes中的index
      const nodeLevel = getNodeLevel(item.id); // 获取节点层级

      const priorNode = nodes.value[nodeIndex - 1]; // 获取列表中前一个节点
      const priorNodeFirstNumber = getFirstIdNumber(priorNode.id); // 获取前一个节点的第一个数字

      if (priorNodeFirstNumber === idFirstNumber) {
        // 同一簇节点
        item.position.y = priorNode.position.y + 70;

        // 如果priorNode为主干，则y位置加上偏移值
        if (priorNode.type === "trunk_node")
          item.position.y += 16;
      }
      else {
        item.position.y = 0;
      }

      if (nodeLevel === 1) {
        // 如果id为1，则设置x位置为0，否则设置为前一簇的最大x坐标加上偏移值
        if (item.id === "1")
          item.position.x = 0;
        else
          item.position.x = getPriorCrowdMaxX(item.id) + 200;
      }
      else {
        // 子节点
        const rootNode = getNodeById(String(idFirstNumber));
        item.position.x = (rootNode?.position.x ?? 0) + 125 * (nodeLevel - 1);
      }
    }
  }

  // 设置根节点位置
  const rootNode = getNodeById(rootNodeId.value);
  if (rootNode) {
    // 获取其他所有节点的x、y的最大值最小值
    const xValues = nodes.value.map(node => node.position.x);
    const yValues = nodes.value.map(node => node.position.y);
    const maxX = Math.max(...xValues);
    const minX = Math.min(...xValues);
    const maxY = Math.max(...yValues);
    const minY = Math.min(...yValues);

    rootNode.position.x = (maxX + minX) / 2;
    rootNode.position.y = 0 - Math.max((maxY + minY) / 2, 200);
  }
}

const onNodeClicked = (nodeEvent: any) => {
  const node = nodeEvent.node;
  selectedNode.value = node;
  isDrawerOpen.value = true;
}

onMounted(() => {
  initNodes();
  initEdges();
  setNodesPosition();
})
</script>

<template>
  <div style="width: 100%; height: 100%; display: flex; flex-direction: row; gap: 0.5rem;">
    <div style="width: 100%;">
      <VueFlow
        :nodes="nodes"
        :edges="edges"
        style="border-radius: 0.5rem; background-color: white;"
        :fit-view-on-init="true"
        :node-types="nodeTypes as NodeTypesObject"
        :study-tree-details="props.studyTreeDetails"
        :tree-name="props.treeName"
        @node-click="onNodeClicked"
      >
        <MiniMap
          node-color="hotpink"
          position="top-left"
          :pannable="true"
        />

        <Controls position="top-right" />
      </VueFlow>
    </div>
    <a-drawer
      :open="isDrawerOpen"
      width="25%"
      :body-style="{ padding: 0 }"
      @close="isDrawerOpen = false"
    >
      <NodeDetails :key="selectedNode?.id" :node="selectedNode!" />
    </a-drawer>
  </div>
</template>

<style lang="scss">
@import "@vue-flow/core/dist/style.css";
@import "@vue-flow/core/dist/theme-default.css";
@import 'https://cdn.jsdelivr.net/npm/@vue-flow/controls@latest/dist/style.css';
</style>
